/*
 * @Description:
 * @Author: Rfan
 * @Date: 2022-04-13 19:22:20
 * @LastEditTime: 2022-11-17 19:46:26
 */

import { Key } from 'react';
import dayjs from 'dayjs';
import { selectItemByKey } from '@/utils/list';
import type { ConfigType } from 'dayjs';
import { cloneDeep } from 'lodash-es';

/**
 * @description: 使用JSON方法拷贝简单对象，浅层次对象
 * @param {object|(string|number)[]} obj
 * @return {object|(string|number)[]} 格式化后的对象、数组
 */
export function jsonClone(obj: object | (string | number)[]) {
  return JSON.parse(JSON.stringify(obj));
}

/**
 * @description 格式化为时间格式
 * @param {ConfigType} time
 * @param {string} format
 * @return {string} 格式化后的时间
 */
export function formatTime(time?: ConfigType, format: string = 'HH:mm:ss'): string {
  return formatDate(time, format);
}

/**
 * @description 格式化为时间格式
 * @param {ConfigType} date
 * @param {string} format
 * @return {string} 格式化后的时间
 */
export function formatDate(date?: ConfigType, format: string = 'YYYY-MM-DD HH:mm:ss'): string {
  return date ? dayjs(date).format(format) : '';
}

/**
 * @description: 扁平数组转树结构
 * @param {any[]} arr 扁平数组
 * @return {any[]} 转换后的树结构
 */
export function arrToTree(arr: any[] = []): any[] {
  const _list = cloneDeep(arr);
  return _list
    .map((cur: any) => {
      const children = _list.filter((item: any) => item.pid === cur.id);
      if (children.length) {
        cur.children = children;
        arrToTree(children);
      }
      return cur;
    })
    .filter((item: any) => !item.pid);
}

/**
 * @description: 树结构转扁平数组
 * @param {any[]} Tree 树结构数据
 * @return {any[]} 转换后的扁平数组
 */
export function treeToArr(Tree: any[] = []): any[] {
  const _list = jsonClone(Tree);
  return _list.reduce((arr: any[], node: any) => {
    const _children = node.children;
    delete node.children;
    return arr.concat([node], _children ? treeToArr(_children) : []);
  }, []);
}

/**
 * @description: 根据节点id查找节点
 * @param {any} list 原树数据
 * @param {Key} id 树节点id
 * @param {string} key 判断字段
 * @return {*} 找到的节点
 */
export function findTreeNodeByKey(list: any[], id: Key, key: string = 'id'): any[] {
  let node = null;
  for (let i = 0; i < list.length; i++) {
    const item = list[i];
    if (item[key] === id) {
      node = item;
      break;
    } else if (item.children?.length > 0) {
      node = findTreeNodeByKey(item.children, id, key);
      if (node) {
        break;
      }
    }
  }
  return node || undefined;
}

/**
 * @description: 根据节点id增加下级节点
 * @param {any} list 原树数据
 * @param {number} id 树节点id
 * @param {any[]} data 新增的节点
 * @return {*} 新的树
 */
export function addTreeNodeById(list: any[], id: number, data: any[]): any[] {
  return list.map((node) => {
    if (node.id === id) {
      return {
        ...node,
        isLeaf: false,
        leafNode: false,
        children: [...(node.children || []), ...data]
      };
    }
    if (node.children) {
      return {
        ...node,
        children: addTreeNodeById(node.children, id, data)
      };
    }
    return node;
  });
}

/**
 * @description: 根据节点id替换响应节点
 * @param {any} list 原树数据
 * @param {number} id 树节点id
 * @param {any[]} data 替换的节点
 * @return {*} 新的树
 */
export function replaceTreeNode(list: any[], id: number, data: any[]): any[] {
  return list.map((node) => {
    if (node.id === id) {
      return {
        ...data,
        children: node.children
      };
    }
    if (node.children) {
      return {
        ...node,
        children: replaceTreeNode(node.children, id, data)
      };
    }
    return node;
  });
}

/**
 * @description: 根据id删除节点
 * @param {any} list 原树数据
 * @param {number} id 要删除的树的节点
 * @param  {any[]} nodeArr
 * @return {*} 新的树
 */
export function findParentNodeById(list: any[], id: number, nodeArr: any[] = []): any[] {
  const _nodeArr = jsonClone(nodeArr);
  const node: any = selectItemByKey(id, list);
  node && _nodeArr.push(node);
  return node?.pid ? findParentNodeById(list, node.pid, _nodeArr) : _nodeArr;
}

/**
 * @description: 根据id删除节点
 * @param {any} list 原树数据
 * @param {number} id 要删除的树的节点
 * @return {*} 新的树
 */
export function deleteTreeNodeById(list: any[], id: number): any[] {
  return list
    .map((node) => {
      if (node.id === id) {
        return undefined;
      }
      if (node.children) {
        const children = deleteTreeNodeById(node.children, id);
        const _node = {
          ...node,
          children
        };
        if (children.length <= 0) {
          _node.isLeaf = true;
          delete _node.children;
        }
        return _node;
      }
      return node;
    })
    .filter((item) => item);
}

/**
 * @description: 将数字转换为EXCEL列
 * @param {number} idx 列索引，要转换的数字
 * @return {string} EXCEL列
 * @example
 * indexToTitle(10) // J
 * indexToTitle(26) // Z
 * indexToTitle(27) // AA
 */
export function indexToTitle(idx: number): string {
  if (idx <= 0) {
    return '';
  }
  const num = idx - 1;
  const arr = idx === 1 ? [num] : [];
  for (let i = num; i > 0; i = Math.floor(i / 26)) {
    arr.unshift(i % 26 === 0 && i !== num ? 26 : i % 26);
    if (i === 26 && i !== num) {
      break;
    }
  }
  arr[arr.length - 1] += 1;
  return arr.map((val) => String.fromCharCode('A'.charCodeAt(0) + val - 1)).join('');
}

/**
 * @description: 判断对象是否为空
 * @param {object} obj 对象
 * @return {boolean} 是否为空
 */
export function isNullObj(obj: { [k: string]: any }): boolean {
  return JSON.stringify(obj) === '{}';
}

/**
 * @description 获取浏览器默认语言
 * @return string
 */
export const getBrowserLang = () => {
  const browserLang = navigator.language;
  let defaultBrowserLang = '';
  if (
    browserLang.toLowerCase() === 'cn' ||
    browserLang.toLowerCase() === 'zh' ||
    browserLang.toLowerCase() === 'zh-cn'
  ) {
    defaultBrowserLang = 'zh';
  } else {
    defaultBrowserLang = 'en';
  }
  return defaultBrowserLang;
};

export const byteConvert = (bytes: number): string => {
  if (isNaN(bytes)) {
    return '';
  }
  const symbols = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
  let exp = Math.floor(Math.log(bytes) / Math.log(2));
  if (exp < 1) {
    exp = 0;
  }
  const i = Math.floor(exp / 10);
  bytes = bytes / Math.pow(2, 10 * i);
  let convertedStr = '';
  if (bytes.toString().length > bytes.toFixed(2).toString().length) {
    convertedStr = bytes.toFixed(2);
  }
  return `${convertedStr} ${symbols[i]}`;
};
